#include "../include/PostProcessor.hpp"
#include "../include/Utils.hpp"
#include <iostream>
using namespace std;
using namespace klas;

PostProcessor::PostProcessor(const Vector2<iReal>& screenSize)
{  
  m_dim = screenSize;

  // Setup FBO
  glGenFramebuffersEXT(1, &m_fboObject);
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboObject);

  // Create the render buffer for depth
  glGenRenderbuffersEXT(1, &m_depthBuffer);
  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer);
  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, m_dim.x, m_dim.y);

  // Now setup a texture to render to
  glGenTextures(1, &m_screenTexture);
  glBindTexture(GL_TEXTURE_2D, m_screenTexture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  m_dim.x, m_dim.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  //  The following 3 lines enable mipmap filtering and generate the mipmap data so rendering works
  //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  //glGenerateMipmapEXT(GL_TEXTURE_2D);

  // And attach it to the FBO so we can render to it
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_screenTexture, 0);

  // Attach the depth render buffer to the FBO as it's depth attachment
  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer);


  GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  if(status != GL_FRAMEBUFFER_COMPLETE_EXT)
  {
    Utils::log("PostProcessor::PostProcessor error: unable to create framebuffer.");
    cout << "PostProcessor::PostProcessor error: unable to create framebuffer.";
  }

  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind the frame buffer
  
}

void PostProcessor::renderingStarted()
{
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboObject);

  // Save the viewport and set it to the size of the texture
  glPushAttrib(GL_VIEWPORT_BIT);
  glViewport(0, 0, m_dim.x, m_dim.y);
}

void PostProcessor::renderingFinished()
{
  glPopAttrib();
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

  glBindTexture(GL_TEXTURE_2D, m_screenTexture);
  //glGenerateMipmapEXT(GL_TEXTURE_2D);
}

void PostProcessor::kill()
{
  if(m_fboObject)
  {
    glDeleteFramebuffersEXT(1, &m_fboObject);
    m_fboObject = NULL;
  }

  if(m_depthBuffer)
  {
    glDeleteRenderbuffersEXT(1, &m_depthBuffer);
    m_depthBuffer = NULL;
  }

  if(glIsTexture(m_screenTexture))
    glDeleteTextures(1, &m_screenTexture);
}

void PostProcessor::processEffects()
{

}

void PostProcessor::render()
{
	// We have to reverse the texture coordinates so that the texture won't render
	// upside down.
	//glClear(GL_COLOR_BUFFER_BIT);
	glPushMatrix();
	glLoadIdentity();
	glColor4f(1.0f, 1.0f, 1.0f, .18f);
  glBindTexture(GL_TEXTURE_2D, m_screenTexture);
    glBegin(GL_QUADS);
      glTexCoord2i(0, 1);
      glVertex3f(0.0, 0.0, 0.0);

      glTexCoord2i(1, 1);
      glVertex3f(m_dim.x, 0.0, 0.0);

      glTexCoord2i(1, 0);
      glVertex3f(m_dim.x, m_dim.y, 0.0);

      glTexCoord2i(0, 0);
      glVertex3f(0.0, m_dim.y, 0.0);
    glEnd();
    
  glPopMatrix();
}
